package com.gy.api.video.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.novelweb.tool.upload.local.LocalUpload;
import cn.novelweb.tool.upload.local.pojo.UploadFileParam;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gy.api.base.R;
import com.gy.api.base.Type;
import com.gy.api.common.file.domain.vo.FileVO;
import com.gy.api.video.dao.ResourceFileDao;
import com.gy.api.video.dao.ResourceFileShardDao;
import com.gy.api.video.domain.po.ResourceFilePO;
import com.gy.api.video.domain.po.ResourceFileShardPO;
import com.gy.api.video.domain.vo.FilePageSearchVO;
import com.gy.api.video.domain.vo.FilePageVO;
import com.gy.api.video.domain.vo.FileUpdateVO;
import com.gy.api.video.service.IFileUploadService;
import com.gy.util.DateUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Transactional
public class FileUploadServiceImpl implements IFileUploadService {
    @Value("${server.url}")
    private String server_url;
    @Value("${server.servlet.context-path}")
    private String context_path;

    @Autowired
    ResourceFileDao fileDao;

    @Autowired
    ResourceFileShardDao fileShardDao;

    @Override
    public R<FileVO> upload(MultipartFile file, String type) {
        R r = new R();

        if (file.isEmpty()) {
            return r.set(Type.FAIL);
        }
        String fileName = file.getOriginalFilename(); // 获取文件名
        String suffixName = "";
        if (fileName.contains(".")) {
            suffixName = fileName.substring(fileName.lastIndexOf("."));// 获取文件的后缀名
        }
        String timeDirectory = DateUtils.getDate("yyyy/MMdd");
        String id = IdUtil.getSnowflakeNextIdStr();
        String newFileName = id + suffixName;//新文件名
        String relativePath = timeDirectory + "/" + newFileName;//文件上传手的相对路径
        String realPath = System.getProperty("user.dir") + "/file/" + relativePath;// 文件上传后的绝对路径
        realPath.replaceAll("//", "/");
        File dest = new File(realPath);
        if (!dest.getParentFile().exists()) {// 检测是否存在目录
            dest.getParentFile().mkdirs();
        }
        ResourceFilePO filePO = new ResourceFilePO();
        try {
            file.transferTo(dest);
            filePO.setId(id);
            filePO.setFileKey(RandomUtil.randomString(12).toUpperCase());
            filePO.setCreateBy(StpUtil.getLoginIdAsString());
            filePO.setFileName(fileName.substring(0,fileName.lastIndexOf(".")));
            filePO.setFileRealPath(realPath);
            filePO.setFileFullPath(server_url +context_path  + "file/" + relativePath);
            filePO.setFileSize(new BigDecimal((float) file.getSize() / 1024).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
            filePO.setFileType(type);
            filePO.setFileSuffix(suffixName);
            filePO.setCreateDate(new Date());
            fileDao.insertSelective(filePO);
        } catch (Exception e) {
//            e.printStackTrace();
            throw new RuntimeException("数据保存失败");
        }
        FileVO vo = new FileVO();
        vo.setFileName(fileName);
        vo.setFileSize(new BigDecimal((float) file.getSize() / 1024).setScale(2, BigDecimal.ROUND_HALF_UP) + "KB");
        vo.setFilePath(server_url+context_path + "file/" + relativePath);
        vo.setType(getFileType(suffixName));
        return r.setData(vo);
    }

    @Override
    public List<FilePageVO> getList(FilePageSearchVO searchVO) {
        return fileDao.getList(searchVO);
    }

    @Override
    public void updateName(FileUpdateVO fileUpdateVO) {
        ResourceFilePO filePO =fileDao.selectByPrimaryKey(fileUpdateVO.getId());
        if(filePO==null){
            throw new RuntimeException("文件不存在");
        }
        filePO.setFileName(fileUpdateVO.getFileName());
        fileDao.updateByPrimaryKeySelective(filePO);
    }

    @Override
    public R checkFileMd5(String md5, String fileName) {
        Example fileExample=new Example(ResourceFileShardPO.class);
        fileExample.and().andEqualTo("fileId",md5);
        fileExample.setOrderByClause("shard_chunk asc");
        List<ResourceFileShardPO> list=fileShardDao.selectByExample(fileExample);
        List<String> missChunkList = new LinkedList();
        if(list!=null&&list.size()>0){
            ResourceFileShardPO one=list.get(0);
            if(list.size()==one.getShardChunks()){
                return new R().setMessage("文件已经上传");
            }
            Map<Integer, Integer> chunkMap = list.stream().collect(Collectors.toMap(ResourceFileShardPO::getShardChunk, ResourceFileShardPO::getShardChunk));
            for (int i = 0; i < one.getShardChunks() ; i++) {
                if(!chunkMap.containsKey(i)){
                    missChunkList.add(Integer.toString(i));
                }
            }
        }
        if(list==null||list.size()==0){
            return new R(Type.EXISTS);
        }
        if(missChunkList==null||missChunkList.size()==0){
            return new R().setMessage("文件已经上传");
        }
        JSONArray jsonArray = JSON.parseArray(JSONObject.toJSONString(missChunkList));
        return new R(Type.EXIST).setData(jsonArray);
    }

    @Override
    public R successFile(String md5, Integer type, String fileName, Long fileSize) {
        Example example=new Example(ResourceFilePO.class);
        example.and().andEqualTo("fileKey",md5);
        ResourceFilePO companyFilePO=fileDao.selectOneByExample(example);
        if(companyFilePO!=null){
            FileVO vo = new FileVO();
            vo.setFileSize(companyFilePO.getFileSize() + "KB");
            vo.setFilePath(companyFilePO.getFileFullPath());
            vo.setType(Integer.parseInt(companyFilePO.getFileType()));
            return new R(vo).setMessage("文件已经上传");
        }
        ResourceFilePO filePO = new ResourceFilePO();
        String id = IdUtil.getSnowflakeNextIdStr();
        filePO.setId(id);

        String suffixName = "";
        if (fileName.contains(".")) {
            suffixName = fileName.substring(fileName.lastIndexOf("."));// 获取文件的后缀名
        }
        filePO.setId(id);
        filePO.setFileSize(new BigDecimal((float) fileSize / 1024).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        filePO.setFileType(type+"");
        filePO.setFileSuffix(suffixName);
        filePO.setCreateDate(new Date());
        filePO.setCreateBy(StpUtil.getLoginIdAsString());
        filePO.setFileKey(RandomUtil.randomString(12).toUpperCase());
        String timeDirectory = DateUtils.getDate("yyyy/MMdd");
        String path = timeDirectory;
        String relativePath = timeDirectory + "/" + fileName;//文件上传手的相对路径
        String realPath = System.getProperty("user.dir") + "/file/" + relativePath;// 文件上传后的绝对路径
        realPath.replaceAll("//", "/");
        filePO.setFileName(fileName);
        filePO.setFileRealPath(realPath);
        filePO.setFileFullPath(server_url +context_path   + "file/" + relativePath);

        fileDao.insertSelective(filePO);
        FileVO vo = new FileVO();
        vo.setFileSize(filePO.getFileSize() + "KB");
        vo.setFilePath(filePO.getFileFullPath());
        vo.setType(getFileType(suffixName));
        return new R().setData(vo);
    }

    @Override
    public R upload_shard(UploadFileParam uploadFileParam, HttpServletRequest request) {
        try {
            String timeDirectory = DateUtils.getDate("yyyy/MMdd");
            String relativePath =  timeDirectory + "/";//文件上传手的相对路径
            String realPath = System.getProperty("user.dir") + "/file/" + relativePath;// 文件上传后的绝对路径
            LocalUpload.fragmentFileUploader(uploadFileParam, realPath+"/conf", realPath, 5242880L, request);
            ResourceFileShardPO resourceFileShardPO=new ResourceFileShardPO();
            resourceFileShardPO.setFileId(uploadFileParam.getMd5());
            resourceFileShardPO.setId(IdUtil.getSnowflakeNextIdStr());
            resourceFileShardPO.setShardChunk(uploadFileParam.getChunk());
            resourceFileShardPO.setShardChunks(uploadFileParam.getChunks());
            resourceFileShardPO.setShardName(uploadFileParam.getName());
            resourceFileShardPO.setShardSize(uploadFileParam.getFile().getSize());
            fileShardDao.insertSelective(resourceFileShardPO);
        }catch (Exception e){
//            e.printStackTrace();
        }
        return new R();
    }


    private Integer getFileType(String suffixName) {
        Integer type = 6;
        //文件类型：1.图片 2.视频 3.网页相关文件 4.压缩包 5.excel文件 6. 其它
        //图片 .jpg .jpeg .gif .png .bmp
        //视频 .mp4 .3gp .m4v .mpg .avi
        //网页相关文件 .html .js .css
        //压缩包 .zip .rar
        //excel文件 .xls .xlsx
        //其它
        switch (suffixName) {
            case ".zip":
                type = 4;
                break;
            case ".rar":
                type = 4;
                break;
            case ".xls":
                type = 5;
                break;
            case ".xlsx":
                type = 5;
                break;
            case ".jpg":
                type = 1;
                break;
            case ".jpeg":
                type = 1;
                break;
            case ".gif":
                type = 1;
                break;
            case ".png":
                type = 1;
                break;
            case ".bmp":
                type = 1;
                break;
            case ".mp4":
                type = 2;
                break;
            case ".3gp":
                type = 2;
                break;
            case ".m4v":
                type = 2;
                break;
            case ".mpg":
                type = 2;
                break;
            case ".mov":
                type = 2;
            case ".wmv":
                type = 2;
            case ".mkv":
                type = 2;
            case ".wav":
                type = 2;
            case ".ts":
                type = 2;
            case ".flv":
                type = 2;
            case ".avi":
                type = 2;
                break;
            case ".html":
                type = 3;
                break;
            case ".css":
                type = 3;
                break;
            case ".js":
                type = 3;
                break;
        }
        return type;
    }
}
